package examples;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gdata.client.analytics.AnalyticsService;
import com.google.gdata.client.analytics.DataQuery;
import com.google.gdata.client.http.AuthSubUtil;
import com.google.gdata.data.analytics.AccountEntry;
import com.google.gdata.data.analytics.AccountFeed;
import com.google.gdata.data.analytics.Aggregates;
import com.google.gdata.data.analytics.DataEntry;
import com.google.gdata.data.analytics.DataFeed;
import com.google.gdata.data.analytics.DataSource;
import com.google.gdata.data.analytics.Dimension;
import com.google.gdata.data.analytics.Metric;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

public class AnalyticsEx extends HttpServlet{
	public void doGet(HttpServletRequest request, HttpServletResponse response)
		throws IOException, ServletException {
		String scope = "https://www.google.com/analytics/feeds/";
		String nextUrl = AuthSubUtil.getRequestUrl( request.getRequestURL().toString(), scope, false, true);
		if (request.getQueryString() == null) {
			response.getWriter().println(nextUrl);
			response.sendRedirect(nextUrl);
		} else {
			// The user is being redirected back from google.com to exchange the AuthSub one time
		    // use token for a session token.
			String requestQuery = request.getQueryString();
			
			// Retrieve single use token from the URL.
		    String singleUseToken = AuthSubUtil.getTokenFromReply(requestQuery);
		    
		    //Get sessionToken
		    String sessionToken = ""; 
		    String authServiceError = "";
		    
		    if (singleUseToken != null) {
		        try {
		        	// Exchange single use token for session token.
		        	sessionToken =  AuthSubUtil.exchangeForSessionToken(singleUseToken, null);

		        } catch (AuthenticationException e) {
		        	authServiceError = e.getMessage();
		        } catch (GeneralSecurityException e) {
		        	authServiceError = e.getMessage();
		        } catch (IOException e) {
		        	authServiceError = e.getMessage();
		        }
			}
		   response.getWriter().println("sessionToken:" + sessionToken);
		   response.getWriter().println("authServiceError:" + authServiceError);
		   printAccountFeed(sessionToken, response);
		   printDataFeed(sessionToken, "58656721", response);
		}
	}
	
	private void printAccountFeed(String sessionToken, HttpServletResponse response) throws IOException {
		//------------------------------------------------------
	    // Configure GA API
	    //------------------------------------------------------
	    AnalyticsService as = new AnalyticsService("gaExportAPI_acctSample_v1.0");
	    String baseUrl = "https://www.google.com/analytics/feeds/accounts/default";

	    //------------------------------------------------------
	    // Client Login Authentication
	    //------------------------------------------------------
	    /*try {
	      as.setUserCredentials(CLIENT_USERNAME, CLIENT_PASS);
	    } catch (AuthenticationException e) {
	      System.err.println("Authentication failed : " + e.getMessage());
	      return;
	    }*/

	    as.setAuthSubToken(sessionToken);
	    
	    //------------------------------------------------------
	    // GA Account Feed
	    //------------------------------------------------------
	    URL queryUrl;
	    try {
	      queryUrl = new URL(baseUrl);
	    } catch (MalformedURLException e) {
	      System.err.println("Malformed URL: " + baseUrl);
	      return;
	    }

	    // Send our request to the Analytics API and wait for the results to come back
	    AccountFeed accountFeed;
	    try {
	      accountFeed = as.getFeed(queryUrl, AccountFeed.class);
	    } catch (IOException e) {
	      System.err.println("Network error trying to retrieve feed: " + e.getMessage());
	      return;
	    } catch (ServiceException e) {
	      System.err.println("Analytics API responded with an error message: " + e.getMessage());
	      return;
	    }

	    //------------------------------------------------------
	    // Format Feed Related Data
	    //------------------------------------------------------
	    // Print top-level information about the feed
	    response.getWriter().println("----------------------------------------------------------------------------------------");
	    response.getWriter().println(
	      "\nFeed Title     = " + accountFeed.getTitle().getPlainText() + 
	      "\nTotal Results  = " + accountFeed.getTotalResults() +
	      "\nStart Index    = " + accountFeed.getStartIndex() +
	      "\nItems Per Page = " + accountFeed.getItemsPerPage() +
	      "\nFeed Id        = " + accountFeed.getId());

	    // Print the feeds' entry data
	    for (AccountEntry entry : accountFeed.getEntries()) {
	      response.getWriter().println(
	        "\nWeb Property Id = " + entry.getProperty("ga:webPropertyId") +
	        "\nAccount Name    = " + entry.getProperty("ga:accountName") +
	        "\nAccount Id      = " + entry.getProperty("ga:accountId") +
	        "\nProfile Name    = " + entry.getTitle().getPlainText() +
	        "\nProfile Id      = " + entry.getProperty("ga:profileId") +
	        "\nTable Id        = " + entry.getTableId().getValue());
	    }
	}
	
	private void printDataFeed(String sessionToken, String profileId, HttpServletResponse response) throws IOException {
		//------------------------------------------------------
	    // Configure GA API
	    //------------------------------------------------------
	    AnalyticsService as = new AnalyticsService("gaExportAPI_acctSample_v1.0");
	    String baseUrl = "https://www.google.com/analytics/feeds/data";
	    DataQuery query;

	    //------------------------------------------------------
	    // Client Login Authentication
	    //------------------------------------------------------
	    /*try {
	      as.setUserCredentials(CLIENT_USERNAME, CLIENT_PASS);
	    } catch (AuthenticationException e) {
	      System.err.println("Error : " + e.getMessage());
	      return;
	    }*/
	    as.setAuthSubToken(sessionToken);

	    //------------------------------------------------------
	    // GA Data Feed
	    //------------------------------------------------------
	    // first build the query
	    try {
	      query = new DataQuery(new URL(baseUrl));
	    } catch (MalformedURLException e) {
	      System.err.println("Malformed URL: " + baseUrl);
	      return;
	    }
	    query.setIds("ga:" + profileId);
	    query.setDimensions("ga:source,ga:medium");
	    query.setMetrics("ga:visits,ga:bounces");
	    query.setSort("-ga:visits");
	    query.setFilters("ga:medium==referral");
	    query.setMaxResults(100);
	    query.setStartDate("2012-06-01");
	    query.setEndDate("2012-06-30");
	    URL url = query.getUrl();
	    response.getWriter().println("URL: " + url.toString());

	    // Send our request to the Analytics API and wait for the results to come back
	    DataFeed feed;
	    try {
	      feed = as.getFeed(url, DataFeed.class);
	    } catch (IOException e) {
	      System.err.println("Network error trying to retrieve feed: " + e.getMessage());
	      return;
	    } catch (ServiceException e) {
	      System.err.println("Analytics API responded with an error message: " + e.getMessage());
	      return;
	    }

	    try {
	    	outputFeedData(feed, response);
		    outputFeedDataSources(feed, response);
		    outputFeedAggregates(feed, response);
		    outputEntryRowData(feed, response);

		    response.getWriter().println("----------------------------------------------------------------------------------------");
		    String tableData = this.getFeedTable(feed);
		    response.getWriter().println(tableData);
		} catch (Exception e) {
			e.printStackTrace();
		}
	    
	}
	
	//------------------------------------------------------
	  // Format Feed Related Data
	  //------------------------------------------------------
	  /**
	   * Output the information specific to the feed.
	   * @param {DataFeed} feed Parameter passed
	   *     back from the feed handler.
	 * @throws IOException 
	   */
	  public void outputFeedData(DataFeed feed, HttpServletResponse response) throws IOException {
		response.getWriter().println("----------------------------------------------------------------------------------------");
	    response.getWriter().println(
	      "\nFeed Title      = " + feed.getTitle().getPlainText() +
	      "\nFeed ID         = " + feed.getId() +
	      "\nTotal Results   = " + feed.getTotalResults() +
	      "\nSart Index      = " + feed.getStartIndex() +
	      "\nItems Per Page  = " + feed.getItemsPerPage() +
	      "\nStart Date      = " + feed.getStartDate().getValue() +
	      "\nEnd Date        = " + feed.getEndDate().getValue());
	  }

	  /**
	  * Output information about the data sources in the feed.
	  * Note: the GA Export API currently has exactly one data source.
	  * @param {DataFeed} feed Parameter passed
	  *     back from the feed handler.
	 * @throws IOException 
	  */
	  public void outputFeedDataSources(DataFeed feed, HttpServletResponse response) throws IOException {
	    DataSource gaDataSource = feed.getDataSources().get(0);
	    response.getWriter().println("----------------------------------------------------------------------------------------");
	    response.getWriter().println(
	      "\nTable Name      = " + gaDataSource.getTableName().getValue() +
	      "\nTable ID        = " + gaDataSource.getTableId().getValue() +
	      "\nWeb Property Id = " + gaDataSource.getProperty("ga:webPropertyId") +
	      "\nProfile Id      = " + gaDataSource.getProperty("ga:profileId") +
	      "\nAccount Name    = " + gaDataSource.getProperty("ga:accountName"));
	  }

	  /**
	  * Output all the metric names and values of the aggregate data.
	  * The aggregate metrics represent values across all of the entries selected 
	  *     by the query and not just the rows returned.
	  * @param {DataFeed} feed Parameter passed
	  *     back from the feed handler.
	 * @throws IOException 
	  */
	  public void outputFeedAggregates(DataFeed feed, HttpServletResponse response) throws IOException {  
	    Aggregates aggregates = feed.getAggregates();
	    List<Metric> aggregateMetrics = aggregates.getMetrics();
	    response.getWriter().println("----------------------------------------------------------------------------------------");
	    for (Metric metric : aggregateMetrics) {
	      response.getWriter().println(
	        "\nMetric Name  = " + metric.getName() +
	        "\nMetric Value = " + metric.getValue() +
	        "\nMetric Type  = " + metric.getType() +
	        "\nMetric CI    = " + metric.getConfidenceInterval().toString());
	    }
	  }

	  /**
	   * Output all the important information from the first entry in the data feed.
	   * @param {DataFeed} feed Parameter passed
	   *     back from the feed handler.
	 * @throws IOException 
	   */
	  public void outputEntryRowData(DataFeed feed, HttpServletResponse response) throws IOException {
	    List<DataEntry> entries = feed.getEntries();
	    if (entries.size() == 0) {
	      response.getWriter().println("No entries found");
	      return;
	    }
	    DataEntry singleEntry = entries.get(0);
	    response.getWriter().println("----------------------------------------------------------------------------------------");
	    // properties specific to all the entries returned in the feed
	    response.getWriter().println("Entry ID    = " + singleEntry.getId());
	    response.getWriter().println("Entry Title = " + singleEntry.getTitle().getPlainText());

	    // iterate through all the dimensions
	    List<Dimension> dimensions = singleEntry.getDimensions();
	    for (Dimension dimension : dimensions) {
	      response.getWriter().println("Dimension Name  = " + dimension.getName());
	      response.getWriter().println("Dimension Value = " + dimension.getValue());
	    }

	    // iterate through all the metrics
	    List<Metric> metrics = singleEntry.getMetrics();
	    for (Metric metric : metrics) {
	      response.getWriter().println("Metric Name  = " + metric.getName());
	      response.getWriter().println("Metric Value = " + metric.getValue());
	      response.getWriter().println("Metric Type  = " + metric.getType());
	      response.getWriter().println("Metric CI    = " + metric.getConfidenceInterval().toString());
	    }
	  }

	  /**
	   * Get the data feed values in the feed as a string.
	   * @param {DataFeed} feed Parameter passed
	   *     back from the feed handler.
	   * @return {String} This returns the contents of the feed.
	   */
	  public String getFeedTable(DataFeed feed) {
	    List<DataEntry> entries = feed.getEntries();
	    if (entries.size() == 0) {
	      return "No entries found";
	    }
	    DataEntry singleEntry = entries.get(0);
	    List<Dimension> dimensions = singleEntry.getDimensions();
	    List<Metric> metrics = singleEntry.getMetrics();
	    List<String> feedDataNames = new ArrayList<String>();
	    String feedDataValues = "";

	    // put all the dimension and metric names into an array
	    for (Dimension dimension : dimensions) {
	      feedDataNames.add(dimension.getName());
	    }
	    for (Metric metric : metrics) {
	      feedDataNames.add(metric.getName());
	    }

	    // put the values of the dimension and metric names into the table
	    for (DataEntry entry : entries) {
	      for (String dataName : feedDataNames) {
	        feedDataValues += "\n" + dataName + "\t= " + entry.stringValueOf(dataName);
	      }
	      feedDataValues += "\n";
	    }
	    return feedDataValues;
	}
}
